package com.qudian.pay.log.aop;

import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.qudian.pay.core.aop.BaseInterceptor;
import com.qudian.pay.core.runtime.ProductContextHolder;
import com.qudian.pay.core.utils.AnnotatedUtils;
import com.qudian.pay.log.annotation.DigestLog;
import com.qudian.pay.log.enums.LoggerPrintType;
import com.qudian.pay.log.model.DefaultDigestLogInfo;
import com.qudian.pay.log.model.LogInfo;

/**
 * @Description: 摘要日志拦截器
 * @ClassName: DigestLogInterceptor
*
 * @date 2015年11月17日 下午10:31:48
 */
public class DigestLogInterceptor extends BaseInterceptor {
	
	@Override
	public Object bizInvoke(MethodInvocation invocation) throws Throwable {
		StopWatch stopWatch = new StopWatch();
		// 开始记录时间
		stopWatch.start();
		String argumentString = null;
		DigestLog digestLog = AnnotatedUtils.getAnnotated(DigestLog.class, invocation);
		boolean hasAnotated = digestLog != null;
		try {
			if (hasAnotated) {
				if (LoggerPrintType.IGNORE_INPUT != digestLog.printType()) {
					argumentString = convert2argumentList(invocation.getArguments());
				}
			}
			// 执行业务方法
			Object result = invocation.proceed();
			if (hasAnotated) {
				if (LoggerPrintType.IGNORE_OUTPUT != digestLog.printType()) {
					digestInvokeLog(invocation.getMethod(), digestLog, stopWatch, result, argumentString, null, true);
				} else {
					digestInvokeLog(invocation.getMethod(), digestLog, stopWatch, null, argumentString, null, true);
				}
			}
			return result;
		} catch (Throwable e) {
			if (hasAnotated) {
				if (LoggerPrintType.IGNORE_INPUT != digestLog.printType()) {
					argumentString = (StringUtils.isBlank(argumentString) ? convert2argumentList(invocation.getArguments()) : argumentString);
				}
				if (LoggerPrintType.IGNORE_EXCEPTION != digestLog.printType()) {
					digestInvokeLog(invocation.getMethod(), digestLog, stopWatch, null, argumentString, e, false);
				} else {
					digestInvokeLog(invocation.getMethod(), digestLog, stopWatch, null, argumentString, null, false);
				}
			}
			throw e;
		}
	}
	
	/**
	 * @Description: 转换请求参数数组为请求参数列表
	 * @param arguments 请求参数数组
	 * @return String 返回类型
	*
	 * @date 2015年11月17日 下午11:30:58
	 */
	private String convert2argumentList(Object[] arguments) {
		String returnStr = "";
		if (null != arguments) {
			try {
				// returnStr = JSON.toJSONString(arguments,
				// SerializerFeature.WriteMapNullValue,
				// SerializerFeature.WriteNullListAsEmpty);
				returnStr = JSON.toJSONString(arguments);
			} catch (Exception e) {
			}
		}
		return returnStr;
	}
	
	protected void digestInvokeLog(Method method, DigestLog digestLog, StopWatch stopWatch, Object result, String arguments, Throwable e,
			boolean isInvokeSuccess) {
		stopWatch.split();
		DefaultDigestLogInfo digestLogInfo = new DefaultDigestLogInfo();
		digestLogInfo.setLogId(ProductContextHolder.getProductContext().getRequestId());
		digestLogInfo.setInterceptorClass(method.getDeclaringClass().getSimpleName());
		digestLogInfo.setInterceptorMethod(method.getName());
		digestLogInfo.setStopWatch(stopWatch);
		digestLogInfo.setLogFileName(digestLog.logFileName());
		digestLogInfo.setLoggerLevel(digestLog.loggerLevel());
		digestLogInfo.setRequestParams(arguments);
		digestLogInfo.setInvokeResult(result);
		digestLogInfo.setException(e);
		digestLogInfo.setInvokeSuccess(isInvokeSuccess);
		printLog(digestLogInfo);
	}
	
	/**
	 * @Description: 输出日志
	 * @param logInfo
	 * @return void 返回类型
	*
	 * @date 2015年11月17日 下午11:32:15
	 */
	protected void printLog(LogInfo logInfo) {
		Logger logger = LoggerFactory.getLogger(logInfo.getLogFileName());
		switch (logInfo.getLoggerLevel()) {
		case DEBUG: {
			logger.debug(logInfo.toLogString());
			break;
		}
		case INFO: {
			logger.info(logInfo.toLogString());
			break;
		}
		case WARN: {
			logger.warn(logInfo.toLogString());
			break;
		}
		case ERROR: {
			logger.error(logInfo.toLogString());
			break;
		}
		default:
			break;
		}
	}
}
